package com.wushijia.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.charset.StandardCharsets;
import java.util.Date;

public class NettyServer {

    private final static Logger logger = LoggerFactory.getLogger(NettyServer.class);

    public static void main(String[] args) {
        // bossGroup表示监听端口，接收新连接的线程组，负责创建新连接
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        // workerGroup表示处理每一个连接的数据读写的线程组。用于读取数据及业务逻辑处理
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(bossGroup, workerGroup);
        bootstrap.channel(NioServerSocketChannel.class);
        // 表示系统用于临时存放已完成三次握手的请求的队列的最大长度，服务端
        bootstrap.option(ChannelOption.SO_BACKLOG, 1024);
        // ChannelOption.TCP_NODELAY表示是否开启Nagle算法，true表示关闭，false表示开启。
        // 通俗地说，如果要求高实时性，有数据发送时就马上发送，就设置为关闭；如果需要减少发送次数，减少网络交互，就设置为开启。
        bootstrap.childOption(ChannelOption.TCP_NODELAY, true);
        // 表示是否开启TCP底层心跳机制，true表示开启
        bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
        // childHandler()方法用于指定处理新连接数据的读写处理逻辑；handler()方法用于指定在服务端启动过程中的一些逻辑
        bootstrap.childHandler(new ChannelInitializer<NioSocketChannel>() {
            // initChannel定义后续每个连接的数据读写; NioSocketChannel是Netty对NIO类型连接的抽象
            @Override
            protected void initChannel(NioSocketChannel socketChannel) throws Exception {
//          ChannelPipeline pipeline = socketChannel.pipeline();
//          pipeline.addLast("decoder", new MessageDecoder());
                socketChannel.pipeline().addLast(new StringDecoder());
                socketChannel.pipeline().addFirst(new FirstServerHandler());
//                socketChannel.pipeline().addLast(new SimpleChannelInboundHandler<String>() {
//                    @Override
//                    protected void channelRead0(ChannelHandlerContext ctx, String msg) {
//                        System.out.println(new Date() + " 服务器端读到数据：" + msg);
//                    }
//                });
            }
        }).bind(9000);
    }

    // 自定义，也可使用SimpleChannelInboundHandler覆盖channelRead0方法
    private static class FirstServerHandler extends ChannelInboundHandlerAdapter {
        // 在接收到客户端发来的数据之后被回调
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            ByteBuf buf = (ByteBuf) msg;
            System.out.println(new Date() + " 从客户端接收数据：" + buf.toString(StandardCharsets.UTF_8));
            // 返回数据到客户端
            ByteBuf out = getByteBuf(ctx);
            ctx.channel().writeAndFlush(out);
        }

        // ByteBuf通过连接的内存管理器创建，字节数据填充到ByteBuf之后才能写到对端。
        private ByteBuf getByteBuf(ChannelHandlerContext ctx) {
            byte[] bytes = "来自服务端的数据".getBytes(StandardCharsets.UTF_8);
            ByteBuf buf = ctx.alloc().buffer();
            buf.writeBytes(bytes);
            return buf;
        }
    }
}
